%%% process_job.erl

-module(process_job).
-export([do_job/1]).

do_job(Job_ID) ->
    server_utils:send_messages(Job_ID, [{request, {worker_code_path, tasks}}]),
	receive
		{ack, {WC_Filename, Tasks}} ->
			ok
	end,
	distribute_work(Job_ID, WC_Filename, Tasks),
    ok = redistribute_work(Job_ID, WC_Filename).

redistribute_work(Job_ID, WC_Filename, 4) -> ok;
redistribute_work(Job_ID, WC_Filename, Count) when Count =< 3 ->
    receive
        {redistribute, {Tasks}} ->
            distribute_work(Job_ID, WC_Filename, Tasks);
        _ ->
            io:fwrite("bad data...")
    end,
    redistribute_work(Job_ID, WC_Filename, Count+1).

distribute_work(Job_ID, WC_Filename, Tasks) ->
	File_Extension = server_utils:get_extension(WC_Filename),
	ask_worker(Job_ID, WC_Filename, server_utils:split_tasks(Tasks), 0).

ask_worker(_, _, [], _) -> ok;
ask_worker(Job_ID, WC_Filename, [Head|Tail], worker100) ->
	Worker = lists:nth(random:uniform(length(nodes())), nodes() ++ [node()]),
	{worker100, Worker} ! {task, Job_ID, WC_Filename, Head}, %TODO switch to use server_utils:send_messages()
	timer:sleep(60000), %60000 ms or 60sec or 1min
	ask_worker(Job_ID, WC_Filename, Tail, worker0);

ask_worker(Job_ID, WC_Filename, [Head|Tail], Worker_Proc) ->
	Worker = lists:nth(random:uniform(length(nodes())), nodes() ++ [node()]),
    if
        Worker == node() ->
            ok = server_utils:send_message(Worker_Proc, [{task, Job_ID, WC_Filename, Head, node()}]);
        _ ->
            ok = server_utils:send_message({Worker, Worker_Proc}, [{task, Job_ID, WC_Filename, Head, node()}])
    end,
	Worker_Number = list_to_integer(lists:nth(1, string:tokens(atom_to_list(Worker_Proc), "worker"))),
	ask_worker(Job_ID, WC_Filename, Tail, server_utils:next_worker(Worker_Number)).

finish_job(Job_ID) ->
    receive
        {request, {do_solution, Data}} ->
            process_solution(Job_ID, Data);
        _ ->
            finish_job(Job_ID)
    end,
    finish_job(Job_ID).

process_solution(Job_ID, Data) ->
    server_utils:send_messages(Job_ID, [{request, {server_code_path, server_code_extension}, self()}]),
    receive
        {ack, {SC_Path, SC_Ext}} ->
            {Compile_Cmd, Execute_Cmd} = build_command(SC_Path, Data, SC_Ext),
            _ = os:cmd(Compile_Cmd),
            Result = os:cmd(Execute_Cmd), %TODO process result, convert to binary
            {Listen_Socket, Address, Port} = server_utils:open_socket(0),
            server_utils:send_messages(Job_ID, [{receive_solution, {Address, Port}, self()}]),
            {ok, Send_Socket} = gen_tcp:accept(Listen_Socket),
            ok = server_utils:send_data(Send_Socket, zlib:zip(Result)),
            receive
                solution_received ->
                    ok
            end,
            ok = server_utils:close_socket(Send_Socket);
            
        _ ->
            finish_job(Job_ID)
    end,

build_command(SC_Path, Data, java) ->
    Compile_Cmd = "javac " ++ SC_Path,
    Execute_Cmd = "java "  ++ SC_Path ++ command_line_args(Solution),
    {Compile_Cmd, Execute_Cmd};
build_command(Job_ID, Data, 'g++') ->
    Compile_Cmd = "g++ "     ++ SC_Path,
    Execute_Cmd = "./a.out " ++ command_line_args(Solution),
    {Compile_Cmd, Execute_Cmd};
build_command(Job_ID, Data, gcc) ->
    Compile_Cmd = "gcc "     ++ SC_Path,
    Execute_Cmd = "./a.out " ++ command_line_args(Solution),
    {Compile_Cmd, Execute_Cmd};
build_command(Job_ID, Data, erl) ->
    Compile_Cmd = "erl -compile "    ++ SC_Path,
    Execute_Cmd = "erl -noshell -s " ++ SC_Path ++ command_line_args(Solution) ++ " -s init stop",
    {Compile_Cmd, Execute_Cmd};
build_command(Job_ID, Data, python) ->
    Execute_Cmd = "python " ++ SC_Path ++ " " ++ command_line_args(Solution),
    {"echo", Execute_Cmd}.
